package tptecnicas.configuration;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import tptecnicas.util.Consts;

/*
 * XMLReader se encarga de parsear el archivo de configuracion .xml para luego
 * devolver una instancia de Configuration. 
 */

public class XmlReader {
	
	private Configuration configuration;
	
	public XmlReader() {
		configuration = new Configuration();
	}
	
	public Configuration readFromXML(InputStream is) throws XMLStreamException {
		XMLInputFactory inputFactory = XMLInputFactory.newInstance();
		XMLStreamReader reader = null;
		try {
			reader = inputFactory.createXMLStreamReader(is);
			readDocument(reader);
		} finally {
			if (reader != null) {
				reader.close();
			}
		}
		return configuration;
	}
	
	public List<String> readCustomXMLFile(InputStream is) throws XMLStreamException {
		XMLInputFactory inputFactory = XMLInputFactory.newInstance();
		XMLStreamReader reader = inputFactory.createXMLStreamReader(is);
		List<String> list = new ArrayList<>();
		//structura xml de tags con unico padre root..
		reader.next();
		while (reader.hasNext()) {
			int eventType = reader.next();
			switch (eventType) {
				case XMLStreamReader.START_ELEMENT:
					list.add(readCharacters(reader));
					break;
				case XMLStreamReader.END_DOCUMENT:
					break;
			}
		}
		if (reader != null) {
			reader.close();
		}
		return list;
	}
	
	private void readDocument(XMLStreamReader reader) throws XMLStreamException {
		while (reader.hasNext()) {
			int eventType = reader.next();
			switch (eventType) {
				case XMLStreamReader.START_ELEMENT:
					String elementName = reader.getLocalName();
					if (elementName.equals("destinos")) {
						readDestinations(reader);
					}
					if (elementName.equals("separador")){
						readSeparator(reader); 
					}
					break;
				case XMLStreamReader.END_ELEMENT:
				case XMLStreamReader.END_DOCUMENT:

					return;
			}
		}
		throw new XMLStreamException("Premature end of file");
	}
	
	private void readDestinations(XMLStreamReader reader) throws XMLStreamException {
		while (reader.hasNext()) {
			int evenType = reader.next();
			switch (evenType) {
			case XMLStreamReader.START_ELEMENT:
				String elementName = reader.getLocalName();
				if (elementName.equals("destino")) {
					readDestination(reader);
				}
				break;
			case XMLStreamReader.END_ELEMENT:
			case XMLStreamReader.END_DOCUMENT:

				return;
			}
		}
		throw new XMLStreamException("Premature end of file");
	}
	
	private String readCharacters(XMLStreamReader reader) throws XMLStreamException {
        StringBuilder result = new StringBuilder();
        while (reader.hasNext()) {
            int eventType = reader.next();
            switch (eventType) {
                case XMLStreamReader.CHARACTERS:
                case XMLStreamReader.CDATA:
                    result.append(reader.getText());
                    break;
                case XMLStreamReader.END_ELEMENT:
                    return result.toString();
            }
        }
        throw new XMLStreamException("Premature end of file");
    }
	
	private void readSeparator(XMLStreamReader reader) throws XMLStreamException {
		configuration.setSeparator(readCharacters(reader));
	}
	
	private void readDestination(XMLStreamReader reader) throws XMLStreamException {
		String destination = reader.getAttributeValue(null, "dest");
		
		if (destination.equals("Terminal")) {
			readTerminalConfig(reader);
		} else if (destination.equals("File")) {
			readFileConfig(reader);
		} else if (destination.equals("Custom")) {
			readCustomConfig(reader);
		}
	}
	
	private void readTerminalConfig(XMLStreamReader reader) throws XMLStreamException {
		String level = "OFF";
		String format = Consts.DEFAULT_FORMAT;
		while (reader.hasNext()) {
			int eventType = reader.next();
			switch(eventType) {
			case XMLStreamReader.START_ELEMENT:
				String elementName = reader.getLocalName();
				if (elementName.equals("level")) {
					level = readCharacters(reader);
				} else if (elementName.equals("format")) {
					format = readCharacters(reader);
				}
				break;
			case XMLStreamReader.END_ELEMENT:
				LogConfig terminalConfig = new LogConfig("Terminal", level, format);
				configuration.addLogConfig(terminalConfig);
				return;
			}
		}
		throw new XMLStreamException("Premature end of file");
	}
	
	private void readFileConfig(XMLStreamReader reader) throws XMLStreamException {
		String path = Consts.DEFAULT_LOGPATH;
		String level = "OFF";
		String format = Consts.DEFAULT_FORMAT;
		while (reader.hasNext()) {
			int eventType = reader.next();
			switch(eventType) {
			case XMLStreamReader.START_ELEMENT:
				String elementName = reader.getLocalName();
				if (elementName.equals("path")) {
					path = readCharacters(reader);
				} else if (elementName.equals("level")) {
					level = readCharacters(reader);
				} else if (elementName.equals("format")) {
					format = readCharacters(reader);
				}
				break;
			case XMLStreamReader.END_ELEMENT:
				LogConfig fileConfig = new LogConfig(path, level, format);
				configuration.addLogConfig(fileConfig);
				return;
			}
		}
		throw new XMLStreamException("Premature end of file");
	}
	
	private void readCustomConfig(XMLStreamReader reader) throws XMLStreamException {
		String path = Consts.DEFAULT_CUSTOMPATH;
		String level = "OFF";
		String format = Consts.DEFAULT_FORMAT;
		while (reader.hasNext()) {
			int eventType = reader.next();
			switch(eventType) {
			case XMLStreamReader.START_ELEMENT:
				String elementName = reader.getLocalName();
				if (elementName.equals("path")) {
					path = readCharacters(reader);
				} else if (elementName.equals("level")) {
					level = readCharacters(reader);
				} else if (elementName.equals("format")) {
					format = readCharacters(reader);
				}
				break;
			case XMLStreamReader.END_ELEMENT:
				LogConfig customConfig = new LogConfig(path, level, format);
				configuration.addLogConfig(customConfig);
				return;
			}
		}
		throw new XMLStreamException("Premature end of file");
	}

}